#include <iostream>
#include <sstream>
#include <cstdlib>
#include <math.h>
#include<algorithm>
#include "AlphaBetaPlayer.h"

using namespace std;

CandidateCell::CandidateCell(int color, Board* board, Cell* cell) :
		mColor(color), mBoard(NULL), mCell(cell), mState(NULL) {
	mColor = color;
	mCell = cell;
	mBoard = new Board(*board);
	mBoard->setStone(cell->getX(), cell->getY(), mColor);
	mState = mBoard->getState();
}

CandidateCell::~CandidateCell() {
	delete mBoard;
}

//bool operator<(const CandidateCell* riLeft, const CandidateCell* riRight) {
//	return riLeft->mState->getPoint(riLeft->mColor) < riRight->mState->getPoint(riLeft->mColor);
//}
//
//bool operator<=(const CandidateCell* riLeft, const CandidateCell* riRight) {
//	return riLeft->mState->getPoint(riLeft->mColor) <= riRight->mState->getPoint(riLeft->mColor);
//}
//
//bool operator>(const CandidateCell* riLeft, const CandidateCell* riRight) {
//	return riLeft->mState->getPoint(riLeft->mColor) >= riRight->mState->getPoint(riLeft->mColor);
//}
//
//bool operator>=(const CandidateCell* riLeft, const CandidateCell* riRight) {
//	return riLeft->mState->getPoint(riLeft->mColor) >= riRight->mState->getPoint(riLeft->mColor);
//}
//
//bool operator==(const CandidateCell* riLeft, const CandidateCell* riRight) {
//	return riLeft->mState->getPoint(riLeft->mColor) == riRight->mState->getPoint(riLeft->mColor);
//}

bool CandidateCell::isWideMarginWon(int color) {
	return mState->isWideMarginWon(color);
}

string CandidateCell::toString() {
	stringstream sb;
	sb << Stone::toString(mColor) << "(" << mCell->getX() << "," << mCell->getY() << "):" << mState->getPoint(mColor);
	return sb.str();
}

AlphaBetaPlayer::AlphaBetaPlayer(string name) :
		Player(name), mMaxDepth(0) {
}

Cell* AlphaBetaPlayer::next() {
	vector<Cell*>* cells = mBoard->findPutableCells(mColor);
	if (cells->empty()) {
		return NULL;
	}
	int value;
	Board* board = new Board(*mBoard);
	mMaxDepth = DEPTH;
//	if (board->getEmptyCellCount() <= 20) {
//		mMaxDepth = board->getEmptyCellCount();
//	}
	Cell* cell = NULL;
	value = search(board, mMaxDepth, MIN, MAX, mColor, Stone::otherColor(mColor), false, cell);
	cout << "value : " << value << endl;

	if (value == MAX) {
		mMind = MIND_WINNER;
	} else if (value == MIN) {
		mMind = MIND_LOOSER;
	}

	Cell* retCell = NULL;
	if (cell != NULL) {
		retCell = mBoard->getCell(cell->getX(), cell->getY());
	}
	delete board;
	return retCell;
}

int AlphaBetaPlayer::search(Board* board, int depth, int alpha, int beta, int myColor, int otherColor, bool pass, Cell*& outCell) {

	int max = alpha;
	Cell* dummyCell = NULL;

	if (depth == 0) {
		vector<CandidateCell*> candidateCells = findPutableCells(board, myColor, otherColor);
		if (candidateCells.empty()) {
			return -Board::State::WON;
		}
		CandidateCell* candidateCell = candidateCells[0];
		int point = candidateCell->mState->getPoint(myColor);
		clear(candidateCells);

		// System.out.println(candidateCell.mState);
		return point;
	}

	vector<Cell*>* cells = board->findPutableCells(myColor);
	vector<CandidateCell*> candidateCells;
	vector<Cell*>::iterator itCells = cells->begin();
	while (itCells != cells->end()) {
		Cell* cell = (*itCells);
		CandidateCell* candidateCell = new CandidateCell(myColor, board, cell);
		if (!candidateCell->isWideMarginWon(otherColor)) {
			candidateCells.push_back(candidateCell);
		}
		++itCells;
	}
	sort(candidateCells.begin(), candidateCells.end(), &CandidateCell::cmp);

	vector<CandidateCell*>::iterator itCandidateCells = candidateCells.begin();
	while (itCandidateCells != candidateCells.end()) {
		CandidateCell* cell = (*itCandidateCells);
		int value = -search(cell->mBoard, depth - 1, -beta, -max, otherColor, myColor, false, dummyCell);
//		if (depth == mMaxDepth) {
//		int repeat = mMaxDepth - depth;
//		if (repeat < 0) {
//			repeat = 0;
//		}
//		cout << std::string(repeat, ' ') << "depth : " << depth << " : " << Stone::toString(myColor) << cell->mCell->toStringData() << " : " << value << " a:"
//				<< alpha << " b:" << beta << endl;
//		}

		if (value > max) {
			max = value;
			outCell = cell->mCell;
			if (max >= beta) {
				return beta;
			}
		}
		++itCandidateCells;
	}
	clear(candidateCells);
	if (cells->empty()) {
		if (pass) {
			if (!candidateCells.empty()) {
				outCell = candidateCells[0]->mCell;
			} else if (!cells->empty()) {
				outCell = (*cells)[0];
			}
			max = board->getState()->getPoint(myColor);
		} else {
			outCell = NULL;
			// Board newBoard = new Board(board);
			max = -search(board, depth, -beta, -max, otherColor, myColor, true, dummyCell);
		}

	}
	return max;

}

vector<CandidateCell*> AlphaBetaPlayer::findPutableCells(Board* board, int myColor, int otherColor) {
	vector<Cell*>* cells = board->findPutableCells(myColor);
	vector<CandidateCell*> candidateCells;

	vector<Cell*>::iterator itCells = cells->begin();
	while (itCells != cells->end()) {
		Cell* cell = (*itCells);
		CandidateCell* candidateCell = new CandidateCell(myColor, board, cell);
		if (!candidateCell->isWideMarginWon(otherColor)) {
			candidateCells.push_back(candidateCell);
		}
		++itCells;
	}
	sort(candidateCells.begin(), candidateCells.end(), &CandidateCell::cmp);
	return candidateCells;
}

void AlphaBetaPlayer::clear(vector<CandidateCell*> cells) {
	vector<CandidateCell*>::iterator it = cells.begin();
	while (it != cells.end()) {
		CandidateCell* cell = (*it);
		delete cell;
		++it;
	}
}
